package com.dynaBlaster.elements;

import java.util.ArrayList;
import com.dynaBlaster.R;
import com.dynaBlaster.core.Point;
import com.dynaBlaster.game.Game;
import com.dynaBlaster.game.GameConfig;
import com.dynaBlaster.game.Terrain;


public class Bomb extends Agent {

	public final static int STATE_TICKING = 0;
	public final static int STATE_EXPLODING = 1;
	public final static int STATE_DEAD = 2;

	public int state = STATE_TICKING;

	Hero owner;

	int range = GameConfig.BOMB_RANGE;

	long stateStartTime;

	// ranges of explosion effects in directions
	public int range_n;
	public int range_s;
	public int range_e;
	public int range_w;

	private ArrayList<Point> toDestroy = new ArrayList<Point>();



	public Bomb(Game game, Point pos, long startMilis, Hero hero) {
		super(game, pos);
		this.stateStartTime = startMilis;
		this.owner = hero;
		hero.incrementBombCount();

		speed = 0;
		size = GameConfig.TILE_SIZE / 2; // bomba ma staly rozwiar na 1 pole



	}

	public boolean isDead() {
		return state == STATE_DEAD;
	}

	public void updateState(long currentTimeMillis) {
		long time_elapsed = currentTimeMillis - stateStartTime;

		switch (state) {
		case STATE_TICKING:
			if (time_elapsed > GameConfig.BOMB_TICKING_TIME) {
				state = STATE_EXPLODING;
				stateStartTime = System.currentTimeMillis();
				computeExplEffects();
			}
			break;
		case STATE_EXPLODING:
			if (time_elapsed > GameConfig.BOMB_EXPLODING_TIME) {
				state = STATE_DEAD;
				stateStartTime = System.currentTimeMillis();
				destroyWalls();
				owner.decrementBombCount();
			}
			break;
		case STATE_DEAD:
			break;
		}

	}

	private void destroyWalls() {
		//for (Point p : toDestroy)
		//	board.board.destroyWall(p);
	}

	private void computeExplEffects() {
		{
			int u = GameConfig.TILE_SIZE;
			int dist;
			Point next, field;
			ArrayList<Bomb> toDetonate = new ArrayList<Bomb>();

			for (int i = 1; i <= range; i++) {// N

				dist = i * u;
				range_n = i;

				next = new Point(pos.x, pos.y - dist);
				field = board.board.getTileInd(next);
				if (game.board.getTileAtIndex(field).terrain == Terrain.WALL) {
					toDestroy.add(field);
					break;
				} else if (game.board.getTileAtIndex(field).terrain == Terrain.CONCRETE) {
					range_n--;
					break;
				} else { // FREE
					Bomb bomb = null;
					// check bombs
					for (Bomb b : game.getBombs())
						if (b.isOverPoint(next)) { // TODO: to bedzie za malo w
													// przypadku latajacych bomb
							bomb = b;
							break;
						}
					if (bomb != null) {
						toDetonate.add(bomb);
						break;
					}
				}
			}
			for (int i = 1; i <= range; i++) {// S

				dist = i * u;
				range_s = i;

				next = new Point(pos.x, pos.y + dist);
				field = board.board.getTileInd(next);
				if (board.board.getTileAtPos(next).terrain == Terrain.WALL) {
					toDestroy.add(field);
					break;
				} else if (board.board.getTileAtPos(next).terrain == Terrain.CONCRETE) {
					range_s--;
					break;
				} else { // FREE
					Bomb bomb = null;
					// check bombs
					for (Bomb b : board.getBombs())
						if (b.isOverPoint(next)) { // TODO: to bedzie za malo w
													// przypadku latajacych bomb
							bomb = b;
							break;
						}
					if (bomb != null) {
						toDetonate.add(bomb);
						break;
					}
				}
			}
			for (int i = 1; i <= range; i++) {// E

				dist = i * u;
				range_e = i;

				next = new Point(pos.x + dist, pos.y);
				field = board.board.getTileInd(next);

				if (game.board.getTileAtPos(next).terrain == Terrain.WALL) {
					toDestroy.add(field);
					break;
				} else if (board.board.getTileAtPos(next).terrain == Terrain.CONCRETE) {
					range_e--;
					break;
				} else { // FREE
					Bomb bomb = null;
					// check bombs
					for (Bomb b : game.getBombs())
						if (b.isOverPoint(next)) { // TODO: to bedzie za malo w
													// przypadku latajacych bomb
							bomb = b;
							break;
						}
					if (bomb != null) {
						toDetonate.add(bomb);
						break;
					}
				}
			}
			for (int i = 1; i <= range; i++) {// W

				dist = i * u;
				range_w = i;

				next = new Point(pos.x - dist, pos.y);
				field = board.board.getTileInd(next);

				if (board.board.getTileAtPos(next).terrain == Terrain.WALL) {
					toDestroy.add(field);
					break;
				} else if (game.board.getTileAtPos(next).terrain == Terrain.CONCRETE) {
					range_w--;
					break;
				} else { // FREE
					Bomb bomb = null;
					// check bombs
					for (Bomb b : board.getBombs())
						if (b.isOverPoint(next)) { // TODO: to bedzie za malo w
													// przypadku latajacych bomb
							bomb = b;
							break;
						}
					if (bomb != null) {
						toDetonate.add(bomb);
						break;
					}
				}
			}

			for (Bomb b : toDetonate) {
				b.nextStateNow();
			}

		}
	}

	private void nextStateNow() {
		stateStartTime = 0;

	}


	@Override
	public boolean touchesCreature(Creature other) {
		switch (state) {
		case STATE_TICKING:
			return false;
		case STATE_EXPLODING:
			int dX = other.pos.x - pos.x;
			int dY = other.pos.y - pos.y;

			dX = Math.abs(dX);
			dY = Math.abs(dY);

			// horizontal expl touch rect
			if (dX < other.size + this.size + range * GameConfig.TILE_SIZE && dY < this.size + other.size)
				return true;
			// vertical expl touch rect
			if (dX < this.size + other.size && dY < other.size + this.size + range * GameConfig.TILE_SIZE)
				return true;

			return false;
		case STATE_DEAD:
			return false;
		}

		return false;
	}

	@Override
	public void move() {
		return;
	}

	public Hero getOwner() {
		return owner;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + range;
		result = prime * result + (int) (stateStartTime ^ (stateStartTime >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Bomb other = (Bomb) obj;
		if (range != other.range)
			return false;
		if (stateStartTime != other.stateStartTime)
			return false;
		return true;
	}

}
